//=========================================================================
// Copyright (C) 2022 The C++ Component Model(COMO) Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=========================================================================

#include "RPCTestUnit.h"
#include <comoapi.h>
#include <comosp.h>
#include <ServiceManager.h>
#include <rpcHelpers.h>
#include <gtest/gtest.h>
#include <stdio.h>
#include <future>

using como::test::rpc::IService;
using jing::ServiceManager;
using jing::RpcHelpers;

static AutoPtr<IService> SERVICE;

TEST(RPCTest, TestGetRPCService)
{
    AutoPtr<IInterface> obj;
    ServiceManager::GetInstance()->GetService("rpcservice", obj);
    SERVICE = IService::Probe(obj);
    EXPECT_TRUE(SERVICE != nullptr);
}

TEST(RPCTest, TestCallTestMethod1)
{
    EXPECT_TRUE(SERVICE != nullptr);
    if (nullptr == SERVICE)
        return;

    ECode ec = E_REMOTE_EXCEPTION;
    Integer result;
    ec = SERVICE->TestMethod1(9, result);
    EXPECT_EQ(9, result);
    EXPECT_EQ(ec, NOERROR);
}

TEST(RPCTest, TestCallTestMethod2)
{
    EXPECT_TRUE(SERVICE != nullptr);
    if (nullptr == SERVICE)
        return;

    ECode ec = E_REMOTE_EXCEPTION;
    Short arg1 = 32767, result1;
    Integer arg2 = 32768, result2;
    Long arg3 = 2147483648, result3;
    Float arg4 = 3.1415926, result4;
    Double arg5 = 3.1415926, result5;
    Boolean arg6 = true, result6;
    Byte arg7 = 0xFF, result7;
    Char arg8 = 0xFF, result8;

    ec = SERVICE->TestMethod2(
            arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
            result1, result2, result3, result4, result5, result6, result7, result8);

    EXPECT_EQ(ec, NOERROR);
    EXPECT_EQ(arg1, result1);
    EXPECT_EQ(arg2, result2);
    EXPECT_EQ(arg3, result3);
    EXPECT_FLOAT_EQ(arg4, result4);
    EXPECT_DOUBLE_EQ(arg5, result5);
    EXPECT_EQ(arg6, result6);
    EXPECT_EQ(arg7, result7);
    EXPECT_EQ(arg8, result8);

}

TEST(RPCTest, TestCallTestMethod3)
{
    EXPECT_TRUE(SERVICE != nullptr);
    if (nullptr == SERVICE)
        return;

    ECode ec = E_REMOTE_EXCEPTION;
    Short arg1 = 32768, result1;
    Integer arg2 = 2147483648, result2;
    Long arg3 = 2147483648, result3;
    Float arg4 = 0.1 + 0.2, result4;
    Double arg5 = 0.1 + 0.2, result5;
    Boolean arg6 = true, result6;
    Byte arg7 = 0xFF, result7;
    Char arg8 = 0xFF, result8;

    ec = SERVICE->TestMethod2(
            arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8,
            result1, result2, result3, result4, result5, result6, result7, result8);

    printf("%d, %d, %lld, %f, %lf, %d, %c, %c\n", result1, result2, result3, result4, result5, result6, result7, result8);

    EXPECT_EQ(ec, NOERROR);
    EXPECT_EQ(arg1, result1);
    EXPECT_EQ(arg2, result2);
    EXPECT_EQ(arg3, result3);
    EXPECT_FLOAT_EQ(0.3, result4);
    EXPECT_DOUBLE_EQ(0.3, result5);
    EXPECT_EQ(arg6, result6);
    EXPECT_EQ(arg7, result7);
    EXPECT_EQ(arg8, result8);
}

TEST(RPCTest, TestAsyncCallTestMethod1)
{
    EXPECT_TRUE(SERVICE != nullptr);
    if (nullptr == SERVICE)
        return;

    ECode ec = E_REMOTE_EXCEPTION;
    Integer result;

    // call the function fnprime() asynchronously
    // ec = SERVICE->TestMethod1(9, result);
    std::future<ECode> fobj = std::async([&result]() -> ECode {
                                    return SERVICE->TestMethod1(9, result);
                                });

    std::future_status status;
    do {
        status = fobj.wait_for(std::chrono::seconds(1));
        if (status == std::future_status::deferred) {
            std::cout << "deferred" << std::endl;
        } else if (status == std::future_status::timeout) {
            std::cout << "timeout" << std::endl;
        } else if (status == std::future_status::ready) {
            std::cout << "ready!" << std::endl;
        }
    } while (status != std::future_status::ready);

    if (status == std::future_status::ready)
        ec = fobj.get();

    EXPECT_EQ(9, result);
    EXPECT_EQ(ec, NOERROR);
}


/*
TEST(RPCTest, TestReleaseStub)
{
    EXPECT_TRUE(SERVICE != nullptr);
    IProxy* proxy = IProxy::Probe(SERVICE);
    EXPECT_TRUE(proxy != nullptr);
    Boolean alive;
    proxy->ReleaseStub(alive);
    EXPECT_TRUE(alive);

    ECode ec = ServiceManager::GetInstance()->RemoveService(String("rpcservice"));
    EXPECT_TRUE(SUCCEEDED(ec));

}
*/
int main(int argc, char **argv)
{
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
